package karaokit.com;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;

import org.farng.mp3.MP3File;
import org.farng.mp3.TagException;
import org.farng.mp3.id3.ID3v1;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class KaraoKitEngine {
	
	/**
	 * Enum defining the different types available for browsing
	 */
	public enum SearchType {Media, Lyrics}; 

	/**
	 * This is the KaraoKit engine. The engen is running through the 
	 * application lifetime and handle the connection between the different 
	 * parts of the system
	 */
	private static KaraoKitEngine Engine = new KaraoKitEngine();
	
	/**
	 * This is the default KarioKit folder
	 */
	public static final String KaraoKitDir = "sdcard/KaraokitFiles/";

	/**
	 * The current loaded lyrics 
	 */
	private Lyrics mCurLyrics;
	
	/**
	 * The current loaded media file 
	 */
	private File mCurMedia;	
	
	/**
	 * The current browsing method
	 */
	private SearchType mCurBrowseType;

	/**
	 * This is a filter for showing media media files while browsing in the 
	 * application.
	 * It filters the files according to the Android Media Player capabilities
	 */
	public static FileFilter MediaFilesFilter  = new FileFilter() {
		public boolean accept(File pathname) {
			String fname = pathname.getName();
			return pathname.isDirectory() ||
			fname.endsWith(".mp3") || fname.endsWith(".wav") || fname.endsWith(".wma") ||
			fname.endsWith(".mid") || fname.endsWith(".xmf") || fname.endsWith(".mxmf") ||
			fname.endsWith(".rtttl") || fname.endsWith(".rtx") || fname.endsWith(".ota");
		}
	};

	/**
	 * This is a filter for showing lyrics files while browsing in the 
	 * application.
	 */
	public static FileFilter LyricsFilter = new FileFilter() {
		public boolean accept(File pathname) {
			return pathname.isDirectory() ||
			pathname.getName().endsWith(".lrc");
		}
	};

	/**
	 * This is the default constructor
	 */
	private KaraoKitEngine() {		
		new File(KaraoKitDir).mkdirs();
	}

	/**
	 * This is a getter for the KaraoKit engine
	 * @return the KaraoKit engine
	 */
	public static KaraoKitEngine GetEngine() {
		return Engine;
	}

	/**
	 * This method handles loading a song to the engine
	 * @param caller the activity that called this method
	 * @param file the song file to load
	 */
	public void loadSong(Context caller, File file) {
		mCurMedia = file; 
		//Check that the fileexists and that its pass the medaia filter
		if (!mCurMedia.exists() || !MediaFilesFilter.accept(mCurMedia)) {
			Log.e("Error in opening the sound file in path:" + 
					mCurMedia.getAbsolutePath(), "");
		}
		Intent player = new Intent(caller, Player.class);		
		caller.startActivity(player);
	}

	/**
	 * This method handles loading a song to the engine
	 * @param path the file path to load to the engine
	 */
	public void loadLyrics(String path) {
		if (new File(path).exists()) 
			mCurLyrics = new Lyrics(new File(path));
	}

	/**
	 * This method set the current media file that is loaded
	 * @param file
	 */
	public void setCurMediaFile(File file) {
		mCurMedia = file;
	}

	/**
	 * This method return the current media file that is loaded
	 * @return the current media file that is loaded
	 */
	public File getCurMediaFile() {
		return mCurMedia;
	}

	/**
	 * This method return the current lyrics that are loaded
	 * @return the current lyrics that are loaded
	 */
	public Lyrics getCurLyrics() {
		return mCurLyrics;
	}

	/**
	 * This method set the current lyrics file and load it 
	 * @param lyrics the lyrics file after parsing
	 */
	public void setCurLyrics(File lyrics) {
		if (lyrics == null) 
			mCurLyrics = null;

		else
			mCurLyrics = new Lyrics(lyrics);
	}

	/**
	 * This method get the next media file to play in alphabetic order
	 * @return the next media file to play
	 */
	public File getNextMediaFile() {
		return getMediaFile(false);
	}

	/**
	 * This method get the previous media file to play in alphabetic order
	 * @returnthe previous media file to play
	 */
	public File getPrevMediaFile() {
		return getMediaFile(true);
	}

	/**
	 * This method return the next media player to play depands on the user 
	 * request (next\prev)
	 * @param prev true iff the user asked to get the previous media file in alphabetic order
	 * @return the next\prev media fileto play
	 */
	private File getMediaFile(boolean prev) {
		File curDir = mCurMedia.getParentFile();			
		File[] files = curDir.listFiles(MediaFilesFilter);
		if (files.length == 1) { // no song to skip to
			return mCurMedia;
		}
		int length = files.length;
		//Searching for the current file and getting the next\prevfile
		for (int i=0; i < length; i++) {
			if (files[i].equals(mCurMedia)) {
				if (prev) {
					if (i==0)
						return files[length-1];
					else
						return files[i-1];
				}
				else { // next song
					if (i==length-1)
						return files[0];
					else
						return files[i+1];
				}				
			}	
		}
		return mCurMedia;
	}

	/**
	 * This method get the ID3v tag from a file that support this format
	 * @return the ID3v tag, or null if the file does not contains such a tag
	 */
	public ID3v1 getMediaProperties() {
		try {
			MP3File mp3file = new MP3File(mCurMedia);
			return mp3file.getID3v1Tag();			
		} catch (IOException e) {
			Log.e("Error opening sound file ", e.getMessage());
		} catch (TagException e) {
			Log.e("Error opening sound file ", e.getMessage());
		}
		return null;
	}

	/**
	 * This method check if a media file is loaded
	 * @return true iff a media file is loaded
	 */
	public boolean isMediaFileLoaded() {
		return (mCurMedia != null);
	}

	/**
	 * This method check if a lyrics file is loaded
	 * @return true iff a lyrics file is loaded
	 */
	public boolean isLyricsLoaded() {
		return (mCurLyrics != null);
	}

	/**
	 * This method starting the browse operation .
	 * @param caller the caller activity
	 * @param type the type that is currently being browsed
	 */
	public void startBrowse(Context caller, SearchType type) {
		mCurBrowseType = type;  
		Intent browserIntent = new Intent(caller, FileBrowser.class);
		caller.startActivity(browserIntent);
	}

	/**
	 * This method update the loaded file according to the user selection, 
	 * and loading the song if the user finished browsing
	 * @param caller the caller activity
	 * @param selectedFile the file selected to load
	 * @param doneBrowsing true iff the user finished browsing and want to 
	 * load the song
	 */
	public void fileSelected(Context caller, File selectedFile, boolean doneBrowsing) {
		switch (mCurBrowseType) {
		case Media:
			mCurMedia = selectedFile;			
			break;
		case Lyrics:
			mCurLyrics = new Lyrics(selectedFile);
			break;
		default: ;
		}
		if (doneBrowsing)
			loadSong(caller, mCurMedia);
	}

	/**
	 * This method handles setting the current browsing type
	 * @param type the current browsing type
	 */
	public void setSearchType(SearchType type) {
		mCurBrowseType = type;
	}

	/**
	 * This method getting the currently search type
	 * @return the currently search type
	 */
	public SearchType getSearchType() {
		return mCurBrowseType;
	}

	/**
	 * This method starts the search activity
	 * @param caller the caller activity
	 */
	public void startSearch(Context caller) {
		Intent searcher = new Intent(caller, Searcher.class);
		caller.startActivity(searcher);
	}
	
	/**
	 * This method starts the about activity
	 * @param caller the caller activity
	 */
	public void startAbout(Context caller) {
		Intent searcher = new Intent(caller, About.class);
		caller.startActivity(searcher);
	}
	
}
